#include "elfparser.h"
#include <QFile>
#include <QDebug>
#include <cstring>

ElfParser::ElfParser(const QString& filename)
    : m_filename(filename), m_valid(false) {
}

ElfParser::~ElfParser() = default;

bool ElfParser::parse() {
    QFile file(m_filename);
    if (!file.open(QIODevice::ReadOnly)) {
        m_error = "Cannot open file: " + file.errorString();
        return false;
    }
    
    m_data = file.readAll();
    file.close();
    
    if (m_data.size() < 64) {
        m_error = "File too small to be ELF";
        return false;
    }
    
    if (!parseHeader()) {
        return false;
    }
    
    parseProgramHeaders();
    parseSectionHeaders();
    parseSymbols();
    parseStrings();
    
    m_valid = true;
    return true;
}

bool ElfParser::isValid() const {
    return m_valid;
}

QString ElfParser::errorString() const {
    return m_error;
}

const ElfHeader& ElfParser::header() const {
    return m_header;
}

const QVector<ProgramHeader>& ElfParser::programHeaders() const {
    return m_programHeaders;
}

const QVector<SectionHeader>& ElfParser::sectionHeaders() const {
    return m_sectionHeaders;
}

const QVector<SymbolEntry>& ElfParser::symbols() const {
    return m_symbols;
}

const QVector<QString>& ElfParser::strings() const {
    return m_strings;
}

bool ElfParser::parseHeader() {
    const char* data = m_data.constData();
    
    // Check ELF magic
    if (memcmp(data, "\177ELF", 4) != 0) {
        m_error = "Not a valid ELF file";
        return false;
    }
    
    uint8_t ei_class = data[4];
    uint8_t ei_data = data[5];
    
    if (ei_class == 1) {
        m_header.elfClass = ElfClass::ELFCLASS32;
    } else if (ei_class == 2) {
        m_header.elfClass = ElfClass::ELFCLASS64;
    } else {
        m_error = "Invalid ELF class";
        return false;
    }
    
    if (ei_data == 1) {
        m_header.elfData = ElfData::ELFDATA2LSB;
    } else if (ei_data == 2) {
        m_header.elfData = ElfData::ELFDATA2MSB;
    } else {
        m_error = "Invalid ELF data encoding";
        return false;
    }
    
    // Parse ELF header
    if (m_header.elfClass == ElfClass::ELFCLASS32) {
        const struct {
            uint16_t type, machine;
            uint32_t version, entry, phoff, shoff;
            uint32_t flags;
            uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstrndx;
        } *hdr32 = reinterpret_cast<const decltype(hdr32)>(data + 16);
        
        m_header.type = hdr32->type;
        m_header.machine = hdr32->machine;
        m_header.version = hdr32->version;
        m_header.entry = hdr32->entry;
        m_header.phoff = hdr32->phoff;
        m_header.shoff = hdr32->shoff;
        m_header.flags = hdr32->flags;
        m_header.ehsize = hdr32->ehsize;
        m_header.phentsize = hdr32->phentsize;
        m_header.phnum = hdr32->phnum;
        m_header.shentsize = hdr32->shentsize;
        m_header.shnum = hdr32->shnum;
        m_header.shstrndx = hdr32->shstrndx;
    } else {
        const struct {
            uint16_t type, machine;
            uint32_t version;
            uint64_t entry, phoff, shoff;
            uint32_t flags;
            uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstrndx;
        } *hdr64 = reinterpret_cast<const decltype(hdr64)>(data + 16);
        
        m_header.type = hdr64->type;
        m_header.machine = hdr64->machine;
        m_header.version = hdr64->version;
        m_header.entry = hdr64->entry;
        m_header.phoff = hdr64->phoff;
        m_header.shoff = hdr64->shoff;
        m_header.flags = hdr64->flags;
        m_header.ehsize = hdr64->ehsize;
        m_header.phentsize = hdr64->phentsize;
        m_header.phnum = hdr64->phnum;
        m_header.shentsize = hdr64->shentsize;
        m_header.shnum = hdr64->shnum;
        m_header.shstrndx = hdr64->shstrndx;
    }
    
    memcpy(m_header.magic, data, 16);
    return true;
}

bool ElfParser::parseProgramHeaders() {
    if (m_header.phnum == 0 || m_header.phoff == 0) {
        return true;
    }
    
    const char* data = m_data.constData();
    
    for (int i = 0; i < m_header.phnum; ++i) {
        ProgramHeader ph;
        const char* ph_data = data + m_header.phoff + i * m_header.phentsize;
        
        if (m_header.elfClass == ElfClass::ELFCLASS32) {
            const struct {
                uint32_t type, offset, vaddr, paddr, filesz, memsz, flags, align;
            } *ph32 = reinterpret_cast<const decltype(ph32)>(ph_data);
            
            ph.type = ph32->type;
            ph.offset = ph32->offset;
            ph.vaddr = ph32->vaddr;
            ph.paddr = ph32->paddr;
            ph.filesz = ph32->filesz;
            ph.memsz = ph32->memsz;
            ph.flags = ph32->flags;
            ph.align = ph32->align;
        } else {
            const struct {
                uint32_t type, flags;
                uint64_t offset, vaddr, paddr, filesz, memsz, align;
            } *ph64 = reinterpret_cast<const decltype(ph64)>(ph_data);
            
            ph.type = ph64->type;
            ph.flags = ph64->flags;
            ph.offset = ph64->offset;
            ph.vaddr = ph64->vaddr;
            ph.paddr = ph64->paddr;
            ph.filesz = ph64->filesz;
            ph.memsz = ph64->memsz;
            ph.align = ph64->align;
        }
        
        m_programHeaders.append(ph);
    }
    
    return true;
}

bool ElfParser::parseSectionHeaders() {
    if (m_header.shnum == 0 || m_header.shoff == 0) {
        return true;
    }
    
    const char* data = m_data.constData();
    
    for (int i = 0; i < m_header.shnum; ++i) {
        SectionHeader sh;
        const char* sh_data = data + m_header.shoff + i * m_header.shentsize;
        
        if (m_header.elfClass == ElfClass::ELFCLASS32) {
            const struct {
                uint32_t sh_name, type, sh_flags, addr, offset, size, link, info, align, entsize;
            } *sh32 = reinterpret_cast<const decltype(sh32)>(sh_data);
            
            sh.sh_name = sh32->sh_name;
            sh.type = sh32->type;
            sh.flags = sh32->sh_flags;
            sh.addr = sh32->addr;
            sh.offset = sh32->offset;
            sh.size = sh32->size;
            sh.link = sh32->link;
            sh.info = sh32->info;
            sh.align = sh32->align;
            sh.entsize = sh32->entsize;
        } else {
            const struct {
                uint32_t sh_name, type;
                uint64_t flags, addr, offset, size;
                uint32_t link, info;
                uint64_t align, entsize;
            } *sh64 = reinterpret_cast<const decltype(sh64)>(sh_data);
            
            sh.sh_name = sh64->sh_name;
            sh.type = sh64->type;
            sh.flags = sh64->flags;
            sh.addr = sh64->addr;
            sh.offset = sh64->offset;
            sh.size = sh64->size;
            sh.link = sh64->link;
            sh.info = sh64->info;
            sh.align = sh64->align;
            sh.entsize = sh64->entsize;
        }
        
        m_sectionHeaders.append(sh);
    }
    
    return true;
}

bool ElfParser::parseSymbols() {
    // 简化实现：查找符号表节
    for (const SectionHeader& sh : m_sectionHeaders) {
        if (sh.type == 2) { // SHT_SYMTAB
            // 解析符号表
            const char* data = m_data.constData();
            uint64_t sym_size = m_header.elfClass == ElfClass::ELFCLASS32 ? 16 : 24;
            uint64_t sym_count = sh.size / sym_size;
            
            for (uint64_t i = 0; i < sym_count; ++i) {
                SymbolEntry sym;
                const char* sym_data = data + sh.offset + i * sym_size;
                
                if (m_header.elfClass == ElfClass::ELFCLASS32) {
                    const struct {
                        uint32_t name, value, size;
                        uint8_t info, other;
                        uint16_t shndx;
                    } *sym32 = reinterpret_cast<const decltype(sym32)>(sym_data);
                    
                    sym.name = sym32->name;
                    sym.value = sym32->value;
                    sym.size = sym32->size;
                    sym.info = sym32->info;
                    sym.other = sym32->other;
                    sym.shndx = sym32->shndx;
                } else {
                    const struct {
                        uint32_t name;
                        uint8_t info, other;
                        uint16_t shndx;
                        uint64_t value, size;
                    } *sym64 = reinterpret_cast<const decltype(sym64)>(sym_data);
                    
                    sym.name = sym64->name;
                    sym.value = sym64->value;
                    sym.size = sym64->size;
                    sym.info = sym64->info;
                    sym.other = sym64->other;
                    sym.shndx = sym64->shndx;
                }
                
                m_symbols.append(sym);
            }
        }
    }
    
    return true;
}

bool ElfParser::parseStrings() {
    // 简化实现：查找字符串表
    for (const SectionHeader& sh : m_sectionHeaders) {
        if (sh.type == 3) { // SHT_STRTAB
            const char* data = m_data.constData();
            const char* str_data = data + sh.offset;
            
            QString current;
            for (uint64_t i = 0; i < sh.size; ++i) {
                if (str_data[i] == '\0') {
                    if (!current.isEmpty()) {
                        m_strings.append(current);
                        current.clear();
                    }
                } else {
                    current += str_data[i];
                }
            }
        }
    }
    
    return true;
}

QString ElfParser::toJson() const {
    QString json = "{\n";
    json += "  \"header\": {\n";
    json += QString("    \"type\": %1,\n").arg(m_header.type);
    json += QString("    \"machine\": %1,\n").arg(m_header.machine);
    json += QString("    \"entry\": \"0x%1\",\n").arg(m_header.entry, 0, 16);
    json += QString("    \"program_headers\": %1,\n").arg(m_header.phnum);
    json += QString("    \"section_headers\": %1\n").arg(m_header.shnum);
    json += "  },\n";
    
    json += "  \"program_headers\": [\n";
    for (int i = 0; i < m_programHeaders.size(); ++i) {
        const ProgramHeader& ph = m_programHeaders[i];
        json += "    {\n";
        json += QString("      \"type\": %1,\n").arg(ph.type);
        json += QString("      \"offset\": \"0x%1\",\n").arg(ph.offset, 0, 16);
        json += QString("      \"vaddr\": \"0x%1\",\n").arg(ph.vaddr, 0, 16);
        json += QString("      \"filesz\": %1,\n").arg(ph.filesz);
        json += QString("      \"memsz\": %1\n").arg(ph.memsz);
        json += i == m_programHeaders.size() - 1 ? "    }\n" : "    },\n";
    }
    json += "  ],\n";
    
    json += "  \"symbols\": [\n";
    for (int i = 0; i < m_symbols.size(); ++i) {
        const SymbolEntry& sym = m_symbols[i];
        json += "    {\n";
        json += QString("      \"value\": \"0x%1\",\n").arg(sym.value, 0, 16);
        json += QString("      \"size\": %1,\n").arg(sym.size);
        json += QString("      \"type\": \"%1\"\n").arg(sym.typeString());
        json += i == m_symbols.size() - 1 ? "    }\n" : "    },\n";
    }
    json += "  ]\n";
    json += "}\n";
    
    return json;
}

QString ElfParser::toText() const {
    QString text;
    text += "ELF Header:\n";
    text += QString("  Type: %1\n").arg(m_header.type);
    text += QString("  Machine: %1\n").arg(m_header.machine);
    text += QString("  Entry Point: 0x%1\n").arg(m_header.entry, 0, 16);
    text += QString("  Program Headers: %1\n").arg(m_header.phnum);
    text += QString("  Section Headers: %1\n\n").arg(m_header.shnum);
    
    text += "Program Headers:\n";
    for (int i = 0; i < m_programHeaders.size(); ++i) {
        const ProgramHeader& ph = m_programHeaders[i];
        text += QString("  [%1] Type: %2, Offset: 0x%3, VAddr: 0x%4, Size: %5\n")
                .arg(i)
                .arg(ph.type)
                .arg(ph.offset, 0, 16)
                .arg(ph.vaddr, 0, 16)
                .arg(ph.filesz);
    }
    
    text += "\nSymbols:\n";
    for (int i = 0; i < m_symbols.size(); ++i) {
        const SymbolEntry& sym = m_symbols[i];
        text += QString("  [%1] Value: 0x%2, Size: %3, Type: %4\n")
                .arg(i)
                .arg(sym.value, 0, 16)
                .arg(sym.size)
                .arg(sym.typeString());
    }
    
    return text;
}
